/**
 * @file TEST_kfifo_canbuffer.c
 * @author Linquan 
 * @brief 
 * @version 0.1
 * @date 2024-12-06
 * 
 * @copyright Copyright (c) 2024
 * 
 */

#include "app_config.h"
#if TEST_KFIFO_CANBUFFER


#include <stdio.h>
#include <stdint.h>
#include "kfifo_sp.h"
#include "string.h"


/********************CAN 报文格式定义 ************************ */
/**> 设置CAN 报文的大小端 */
#define UNKNOWN_ENDIAN   0
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN    1
#define BIG_ENDIAN       2
#endif
#define CHIP_ENDIAN      LITTLE_ENDIAN


typedef union {
    uint32_t exdid;
    uint16_t stdid; 
    struct {
#if (CHIP_ENDIAN == BIG_ENDIAN)
        uint8_t p_r_dp;
        uint8_t pf;
        uint8_t ps;
        uint8_t sa;
#elif (CHIP_ENDIAN == LITTLE_ENDIAN)
        uint8_t sa;
        uint8_t ps;
        uint8_t pf;
        uint8_t p_r_dp;
#else
    #error "J1939Id"
#endif        
    } J1939Id;
} CanIdStr;

typedef struct 
{
    CanIdStr    canid;
    uint8_t     exd; /* 0-Standard, 1-Extend */
    uint8_t     len;	
    uint8_t     data[8];
	#define   CANEXDID  canid.exdid
    #define   CANSTDID  canid.stdid
    #define   J1939ID   canid.J1939Id
    #define   J1939PRDP canid.J1939Id.p_r_dp
    #define   J1939PF   canid.J1939Id.pf
    #define   J1939SA   canid.J1939Id.sa
    #define   J1939PS   canid.J1939Id.ps
   
}STR_CAN_STD_TYPE;      
/********************CAN 报文格式定义 ************************ */

/********************CAN 缓冲区操作定义 ************************ */

/**> CAN报文 处理回调 */
typedef void(*can_fram_anaylise)(STR_CAN_STD_TYPE *can_fram);

/**> 声明缓冲区: 最大存储64条报文 */
DECLARE_KFIFO(can_buffer, STR_CAN_STD_TYPE, 64);

/**
 * @brief CAN 缓冲区初始化
 * 
 */
void can_buffer_init()
{
	INIT_KFIFO(can_buffer);
}

/**
 * @brief 检查缓冲区是否有数据
 * 
 * @return uint8_t 无数据返回0
 */
uint8_t check_can_buffer_is_empty()
{
	return kfifo_used(&can_buffer);
}

/**
 * @brief 向缓冲区追加数据
 * 多用于 CAN中断函数中
 * 
 * @param can_fram 一条CAN报文
 */
void canbuffer_append(STR_CAN_STD_TYPE *can_fram)
{
	kfifo_in(&can_buffer, can_fram, 1);
}

/**
 * @brief 从缓冲区取出数据，并调用回调函数处理
 * 多用在主循环中。
 * @param fram_anaylyse 报文处理回调函数
 * @param max_num 一次最大处理报文数量
 */
void canbuffer_handle(can_fram_anaylise fram_anaylyse, uint8_t max_num)
{
	uint8_t result = 0;
	STR_CAN_STD_TYPE can_fram;
	
    /**> 一次最大处理报文数量 */
    #define HANDLE_MAX_NUM   8

	for(int i = 0; i < max_num; i++)
	{
		result = kfifo_out(&can_buffer, &can_fram, 1);
	
		if( result != 0 ) 
		{
			fram_anaylyse(&can_fram);
		}
		else
		{
			return;
		}
	}
}

/********************CAN 缓冲区操作定义 ************************ */

/********************CAN 缓冲区使用实例 ************************ */

/**> 报文处理的回调函数，打印报文的ID */
void fram_anaylse_callback(STR_CAN_STD_TYPE *can_fram)
{
    B_CYAN_PRINT("can id: %#x\n", can_fram->CANEXDID);
}


void TEST_canbuffer(void * ptr)
{
    /**> 首先初始化 */
    can_buffer_init();

    /**> 假设有 4条报文 */
    STR_CAN_STD_TYPE can_fram_1 = {.CANEXDID = 0XA1111};
    STR_CAN_STD_TYPE can_fram_2 = {.CANEXDID = 0XB2222};
    STR_CAN_STD_TYPE can_fram_3 = {.CANEXDID = 0XC3333};
    STR_CAN_STD_TYPE can_fram_4 = {.CANEXDID = 0XD4444};
    STR_CAN_STD_TYPE can_fram_5 = {.CANEXDID = 0XE5555};

    /**> 不按照顺序填入缓冲区 */
    canbuffer_append(&can_fram_2);
    canbuffer_append(&can_fram_1);
    canbuffer_append(&can_fram_4);
    canbuffer_append(&can_fram_3);
    canbuffer_append(&can_fram_5);

    /**> 模拟 主循环，执行两次处理函数，每次最大处理2条报文 */
    canbuffer_handle(&fram_anaylse_callback, 2);
    canbuffer_handle(&fram_anaylse_callback, 2);
    canbuffer_handle(&fram_anaylse_callback, 2);
}
EXPORT_Lv6_APP_SINGLE(TEST_canbuffer, NULL);



#endif





